package com.wisnews.util;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * Jackson工具类
 * </p>
 */
@Slf4j
public final class JsonUtil {

	private static final ObjectMapper MAPPER = new ObjectMapper();
	static {
		// 设置地点为中国
		MAPPER.setLocale(Locale.CHINA);
		// 去掉默认的时间戳格式
		MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		// 设置为中国上海时区
		MAPPER.setTimeZone(TimeZone.getTimeZone("PRC"));
		// 序列化时，日期的统一格式
		MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA));
		// 序列化处理
		// 这个特性，决定了解析器是否将自动关闭那些不属于parser自己的输入源。
		// 如果禁止，则调用应用不得不分别去关闭那些被用来创建parser的基础输入流InputStream和reader；
		// 默认是true
		MAPPER.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
		// 是否允许解析使用Java/C++ 样式的注释（包括'/'+'*' 和'//' 变量）
		MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
		// 反序列化是是否允许属性名称不带双引号
		MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
		// 是否允许单引号来包住属性名称和字符串值
		MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		// null的属性不序列化
		MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		// 按字母顺序排序属性,默认false
		MAPPER.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
		// 是否以类名作为根元素，可以通过@JsonRootName来自定义根元素名称,默认false
		MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
		// 是否缩放排列输出,默认false
		MAPPER.configure(SerializationFeature.INDENT_OUTPUT, false);
		// 序列化Date日期时以timestamps输出，默认true
		MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
		// 序列化枚举是否以toString()来输出，默认false，即默认以name()来输出
		MAPPER.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
		// 序列化枚举是否以ordinal()来输出，默认false
		MAPPER.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, false);
		// 序列化单元素数组时不以数组来输出，默认false
		MAPPER.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
		// 序列化Map时对key进行排序操作，默认false
		MAPPER.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
		// 序列化char[]时以json数组输出，默认false
		MAPPER.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, true);
		MAPPER.findAndRegisterModules();
		// 失败处理
		MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		// 单引号处理
		MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		// 反序列化时，属性不存在的兼容处理s
		MAPPER.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		// 日期格式化
		MAPPER.registerModule(new JavaTimeModule());
		MAPPER.findAndRegisterModules();
	}

	private JsonUtil() {
	}

	/**
	 * 将对象序列化成json字符串
	 * 
	 * @param value javaBean
	 * @param <T>   T 泛型标记
	 * @return jsonString json字符串
	 */
	public static <T> String obj2Json(T value) {
		try {
			return MAPPER.writeValueAsString(value);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 将对象序列化成 json byte 数组
	 * 
	 * @param object javaBean
	 * @return jsonString json字符串
	 */
	public static byte[] obj2JsonBytes(Object object) {
		try {
			return MAPPER.writeValueAsBytes(object);
		} catch (JsonProcessingException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json反序列化成对象
	 * 
	 * @param content   content
	 * @param valueType class
	 * @param <T>       T 泛型标记
	 * @return Bean
	 */
	public static <T> T json2Obj(String content, Class<T> valueType) {
		try {
			return MAPPER.readValue(content, valueType);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 将json反序列化成对象
	 * 
	 * @param content       content
	 * @param typeReference 泛型类型
	 * @param <T>           T 泛型标记
	 * @return Bean
	 */
	@SuppressWarnings("unchecked")
	public static <T> T json2Obj(String content, TypeReference<?> typeReference) {
		try {
			return (T) MAPPER.readValue(content, typeReference);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json byte 数组反序列化成对象
	 * 
	 * @param bytes     json bytes
	 * @param valueType class
	 * @param <T>       T 泛型标记
	 * @return Bean
	 */
	public static <T> T jsonBytes2Obj(byte[] bytes, Class<T> valueType) {
		try {
			return MAPPER.readValue(bytes, valueType);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json反序列化成对象
	 * 
	 * @param bytes         bytes
	 * @param typeReference 泛型类型
	 * @param <T>           T 泛型标记
	 * @return Bean
	 */
	@SuppressWarnings("unchecked")
	public static <T> T jsonBytes2Obj(byte[] bytes, TypeReference<?> typeReference) {
		try {
			return (T) MAPPER.readValue(bytes, typeReference);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json反序列化成对象
	 * 
	 * @param in        InputStream
	 * @param valueType class
	 * @param <T>       T 泛型标记
	 * @return Bean
	 */
	public static <T> T json2Obj(InputStream in, Class<T> valueType) {
		try {
			return MAPPER.readValue(in, valueType);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json反序列化成对象
	 * 
	 * @param in            InputStream
	 * @param typeReference 泛型类型
	 * @param <T>           T 泛型标记
	 * @return Bean
	 */
	@SuppressWarnings("unchecked")
	public static <T> T json2Obj(InputStream in, TypeReference<?> typeReference) {
		try {
			return (T) MAPPER.readValue(in, typeReference);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json反序列化成List对象
	 * 
	 * @param content      content
	 * @param valueTypeRef class
	 * @param <T>          T 泛型标记
	 * @return List
	 */
	public static <T> List<T> json2List(String content, Class<T> valueTypeRef) {
		try {
			return MAPPER.readValue(content,
					TypeFactory.defaultInstance().constructCollectionLikeType(List.class, valueTypeRef));
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static Map<String, Object> json2Map(String content) {
		try {
			return MAPPER.readValue(content, Map.class);
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static <T> Map<String, T> json2Map(String content, Class<T> valueTypeRef) {
		try {
			Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) MAPPER.readValue(content,
					new TypeReference<Map<String, T>>() {
					});
			Map<String, T> result = new HashMap<>(16);
			for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
				result.put(entry.getKey(), map2Pojo(entry.getValue(), valueTypeRef));
			}
			return result;
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	public static <T> T map2Pojo(Map<?, ?> fromValue, Class<T> toValueType) {
		return MAPPER.convertValue(fromValue, toValueType);
	}

	/**
	 * 将json字符串转成 JsonNode
	 * 
	 * @param jsonString jsonString
	 * @return jsonString json字符串
	 */
	public static JsonNode json2Node(String jsonString) {
		try {
			return MAPPER.readTree(jsonString);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json字符串转成 JsonNode
	 * 
	 * @param in InputStream
	 * @return jsonString json字符串
	 */
	public static JsonNode json2Node(InputStream in) {
		try {
			return MAPPER.readTree(in);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json字符串转成 JsonNode
	 * 
	 * @param content content
	 * @return jsonString json字符串
	 */
	public static JsonNode json2Node(byte[] content) {
		try {
			return MAPPER.readTree(content);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	/**
	 * 将json字符串转成 JsonNode
	 * 
	 * @param jsonParser JsonParser
	 * @return jsonString json字符串
	 */
	public static JsonNode json2Node(JsonParser jsonParser) {
		try {
			return MAPPER.readTree(jsonParser);
		} catch (IOException e) {
			throw wrapRuntime(e);
		}
	}

	public static RuntimeException wrapRuntime(Throwable throwable) {
		if ((throwable instanceof RuntimeException)) {
			return (RuntimeException) throwable;
		}
		return new RuntimeException(throwable);
	}
}
